<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"/>
<title>实体解析</title><link href="../zdoc.css" rel="stylesheet" type="text/css"/><link href="../_rs/site.css" rel="stylesheet" type="text/css"/><script src="../_rs/jquery.js" language="Javascript"></script><script src="../_rs/site.js" language="Javascript"></script><script src="../_rs/z.js" language="Javascript"></script>
</head>
<body><a name="top"></a>
<div class="zdoc_header">实体解析</div>
<div class="zdoc_author"><em>By:</em><b>zozoh</b><a href="mailto:zozohtnt@gmail.com">&lt;zozohtnt@gmail.com&gt;</a></div>
<div class="zdoc_body">
<ul class="zdoc_index_table">
<li>
<div><span class="num">1</span><a href="#什么是实体解析">什么是实体解析</a></div>
</li>
<li>
<div class="zdoc_folder"><span class="num">2</span><a href="#默认的注解解析">默认的注解解析</a></div>
<ul>
<li>
<div><span class="num">2.1</span><a href="#声明实体对应的表名">声明实体对应的表名</a></div>
</li>
<li>
<div><span class="num">2.2</span><a href="#描述字段">描述字段</a></div>
</li>
</ul>
</li>
<li>
<div><span class="num">3</span><a href="#EntityMaker_接口">EntityMaker 接口</a></div>
</li>
<li>
<div><span class="num">4</span><a href="#动态实体">动态实体</a></div>
</li>
</ul>
<div class="hr"><b></b></div>
<h1><a name="什么是实体解析"></a>什么是实体解析</h1>
<div style="float:right;"><a href="#top">Top</a></div>
<p>对于任何一个 ORM 工具，大都是根据配置者约定了解你打算怎么把一张数据表与你的 Java 对象映射到一起。默认的 Nutz.Dao 采用 Java 注解(Annotation) 的方式描述这个映射，但是，当然世界上还有很多其它的映射方式，比如用各种配置文件，比如 JPA 的注解，或者你很想把这个映射关系写在数据库的几张表里，甚至一个 Excel 表格里（你就觉得这样很酷）</p>
<p>从 1.b.38 之后，Nutz.Dao 开放了自己的 Entity 接口，你就可以定义自己的映射存放方式了。</p>
<pre>Class&lt;?&gt;  ---&gt;  Entity&lt;?&gt; ---&gt; PojoMaker ---&gt; DaoStatement ---&gt; DaoExecutor ---&gt; JDBC
           |               |              |                 |                |
           \------------------------ NutDao 的实现流程 -----------------------/
</pre>
<p>从上图，我们可以清楚的看到，Nutz.Dao 会首先分析你传入的 Class&lt;?&gt;，然后将将映射关系保存成一个 Entity&lt;?&gt;，也就是说通过找个 Entity&lt;?&gt;，NutDao 可以了解到调用者打算怎么映射数据表和Java类。</p>
<p>通过 EntityMaker 接口，Nutz 封装了这个过程，你可以重载 NutDao 的一个函数:</p>
<pre>public class MyDao extends NutDao {

    protected EntityMaker createEntityMaker() {
        return new MyEntityMaker();
    }
}
</pre>
<p>之后，如果使用 MyDao，那么实体的生成方式就是你说了算啦 ^_^</p>
<div class="hr"><b></b></div>
<h1><a name="默认的注解解析"></a>默认的注解解析</h1>
<div style="float:right;"><a href="#top">Top</a></div>
<p>通过在你的 POJO 类上标注注解，可以让 Nutz 来理解你打算怎么映射字段，这里我们举几个例子</p>
<h2><a name="声明实体对应的表名"></a>声明实体对应的表名</h2>
<div style="float:right;"><a href="#top">Top</a></div>
<pre>@Table
public class PetBean {
    ...
</pre>
<ul type="disc">
<li>将对应到数据表 "pet_bean"</li>
<li>@Table("t_pet") 将对应到 "t_pet"</li>
</ul>
<h2><a name="描述字段"></a>描述字段</h2>
<div style="float:right;"><a href="#top">Top</a></div>
<pre>@Column //提醒一下,对于@Name注解来说这一行是多余的
@Name
@ColDefine(type=ColType.VARCHAR, width=20)
private String name;
</pre>
<ul type="disc">
<li>将对应到数据表的 "name" 字段 -- 默认用 field 的名字</li>
<li>如果 @Column("nm") 将对应到数据表的 "nm" 字段</li>
<li>@Name 表示这个字段有唯一性约束，你可以 Pet pet = dao.fetch(Pet.class,"abc");</li>
<li>@Name(casesensitive=false) 表示依靠这个字段 fetch 时，忽略大小写</li>
<li>@ColDefine 是给出这个字段最精确的描述，比如上例就是 VARCHAR(20)
<ul type="circle">
<li>@ColDefine 不是必须的，你如果没有声明，Nutz.Dao 会根据字段类型进行猜测</li>
<li>通常，它能猜对，但是对于 String 类型的字段，它实在不知到长度为多少为好</li>
<li>所以它会给一个默认的长度，但是很有可能你希望给一个别的长度</li>
<li>@ColDefine 主要是为 dao.create(XXX.class) 设计的，因为它要生成建表语句</li>
</ul>
</li>
</ul>
<p>通常一个字段，你只需要:</p>
<pre>@Column
private int age;

@Column("pname")
private String parentName;
</pre>
<p>如果你的 POJO 没有任何一个字段标注了 @Column，那么相当于你所有的字段都是数据库字段。否则，仅仅是标注了 @Column 的字段才被认为是数据库字段</p>
<div class="hr"><b></b></div>
<h1><a name="EntityMaker_接口"></a>EntityMaker 接口</h1>
<div style="float:right;"><a href="#top">Top</a></div>
<p>EntityMaker 接口负责具体的 Entity 生成，你可以参看一下它的源代码:</p>
<pre>package org.nutz.dao.entity;

public interface EntityMaker {
        &lt;T&gt; Entity&lt;T&gt; make(Class&lt;T&gt; type);
}
</pre>
<p>Entity&lt;T&gt; 也是一个接口，当然，默认实现类 NutEntity&lt;T&gt; 应该能满足你大多数需求，我想至力于想扩展 Entity 生成方式的同学，会直接阅读相关的源代码作为参考，所以这里就不啰嗦了。</p>
<div class="hr"><b></b></div>
<h1><a name="动态实体"></a>动态实体</h1>
<div style="float:right;"><a href="#top">Top</a></div>
<p>在 1.b.38 之前的版本，曾经记得有个朋友提出一个意见，他希望:</p>
<pre>Map&lt;String,Object&gt; map = new HashMap&lt;String,Object&gt;();
map.put("name", "abc");
map.put("age", 18);
dao.update(map);    // 这个是不会有编译错误的
</pre>
<p>我记得当时我们的理由是：“搞不定呀，我们不知道表名呀””</p>
<p>现在，我们已经支持了这个特性:</p>
<pre>Map&lt;String,Object&gt; map = new HashMap&lt;String,Object&gt;();
map.put(".table", "t_person");
map.put("name", "abc");
map.put("age", 18);
dao.update(map); 
</pre>
<p>你给的 Map 只要多一个固定的名值对 ".table"，那么我就能知道你想操作的数据库表名。所以，你还可以:</p>
<pre>Map&lt;String,Object&gt; map = new HashMap&lt;String,Object&gt;();
map.put(".table", "t_person");
map.put("name", "abc");
map.put("age", 18);
dao.insert(map); 
</pre>
<p>实际上，NutDao 是根据给定的 Map，先构建了一个 Entity&lt;?&gt;，然后之后的事情就顺理成章了。这个特性从另外一方面也验证了现在的实体机制，它的确工作的还不错 :)</p>
</div>
<div class="zdoc_footer"><em>By:</em><b>zozoh</b><a href="mailto:zozohtnt@gmail.com">&lt;zozohtnt@gmail.com&gt;</a></div>
</body>
</html>